/*
Server
*/

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <WinSock2.h>

#pragma comment(lib, "Ws2_32.lib")

#define SERVER_PORT 23505
#define SERVER_IP ADDR_ANY//inet_addr("127.0.0.1");
#define SERVER_LISTEN_BACKLOG 5

const int bufferSize = 32;

BOOL IsWSAStartupFailed(int wsastartupResult)
{
	return wsastartupResult != NO_ERROR;
}

void PrintLine(const char * format, ...)
{
	char lineFormat[32];
	sprintf(lineFormat, "%s\n", format);


	va_list arg;
	int done;

	va_start (arg, format);

	done = vfprintf (stdout, lineFormat, arg);

	va_end (arg);
}

void ExitWithPause(int errorCode)
{
	system("pause");
	exit(errorCode);
}

BOOL IsOperator(const char ch)
{
	if(ch == '+' || ch == '-' || ch == '*' || ch == '/')
	{
		return TRUE;
	}

	return FALSE;
}

BOOL IsValidExpression(const char * expression)
{
	int expressionLength = strlen(expression);

	//2;2;+

	if(expressionLength < 5)
	{
		return -1;
	}

	int numberCount = 0,
		separatorCount = 0,
		symbolCount = 0;

	for (int i = 0; i < expressionLength; i++)
	{
		char ch = expression[i];

		if(isdigit(ch))
		{
			numberCount++;
		}
		else if(ch == ';'){
			separatorCount++;
		}
		else if(ispunct(ch)){
			symbolCount++;
		}
	}

	char opr = expression[expressionLength-1];

	if (separatorCount != 2 || numberCount < 2 || symbolCount != 1 || !IsOperator(opr))
	{
		return FALSE;
	}

	return TRUE;
}

int CalculateExpression(const char * expression)
{
	//Format Exampe: 10;12;+

	int expressionLength = strlen(expression);

	if(!IsValidExpression(expression))
	{
		return -1;
	}

	int Nums[2],
		i = 0;

	char Opr = expression[expressionLength-1];

	for (int k = 0; k < 2; k++)
	{
		char * chNum = new char(),
			* ptrNum = chNum;
		int chNumCount = 0;

		do
		{
			*ptrNum = expression[i];
			ptrNum++;
		} while (expression[++i] != ';');

		i++;
		*ptrNum = '\0';

		Nums[k] = atoi(chNum);
	}

	switch (Opr)
	{
	case '+':
		return Nums[0] + Nums[1];
	case '-':
		return Nums[0] - Nums[1];
	case '*':
		return Nums[0] * Nums[1];
	case '/':
		return Nums[0] / Nums[1];
	}

	return -1;
}

int main()
{
	WSADATA wsa;
	WORD requestedVersion = MAKEWORD(2, 2);

	//wsastartup
	int wsaResult = WSAStartup(requestedVersion, &wsa);

	PrintLine("WSAStartup()...");
	if(IsWSAStartupFailed(wsaResult))
	{
		PrintLine("Error in WSAStartup()");
		ExitWithPause(1);
	}
	PrintLine("WSAStartup() done");

	//socket
	PrintLine("sock()...");
	SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
	PrintLine("socket() done");

	sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(SERVER_PORT);
	serverAddr.sin_addr.s_addr = SERVER_IP;

	//bind
	PrintLine("bind()...");
	int bindResult = bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));

	if(bindResult == SOCKET_ERROR)
	{
		PrintLine("Error in bind()");
		ExitWithPause(1);
	}
	PrintLine("bind() done");

	//listen
	PrintLine("listen()...");
	int listenResult = listen(serverSocket, SERVER_LISTEN_BACKLOG);

	if(listenResult == SOCKET_ERROR)
	{
		PrintLine("Error in listen()");
		ExitWithPause(1);
	}
	PrintLine("listen() done");

	//accept
	while (true)
	{
		PrintLine("Accepting client...");
		SOCKET clientSocket = accept(serverSocket, 0, 0);

		if(clientSocket == INVALID_SOCKET)
		{
			PrintLine("Error in accept()");
			continue;
		}
		PrintLine("Client accepted");

		char expression[bufferSize];

		PrintLine("recv()...");
		int receiveLen = recv(clientSocket, expression, bufferSize, 0);

		//problem in receive
		if(receiveLen == SOCKET_ERROR)
		{
			PrintLine("Error in recv()");

			shutdown(clientSocket, SD_BOTH);
			closesocket(clientSocket);

			PrintLine("Client socket is closed");

			continue;
		}
		//calculate and send
		else
		{
			PrintLine("recv() done");

			expression[receiveLen] = '\0';

			char response[bufferSize];
			int result = CalculateExpression(expression);

			PrintLine("Calculation Result: %d", result);

			if(result == -1)
			{
				sprintf(response, "%s", "Invalid expression");
			}
			else
			{
				sprintf(response, "%d", result);
			}

			PrintLine("Sending response: %s", response);

			int sentSize = send(clientSocket, response, strlen(response), 0);

			if (sentSize == SOCKET_ERROR)
			{
				PrintLine("Error in send()");

				shutdown(clientSocket, SD_BOTH);
				closesocket(clientSocket);

				PrintLine("Client socket is closed");

				continue;
			}

			PrintLine("Response sent");
		}

		shutdown(clientSocket, SD_BOTH);
		closesocket(clientSocket);

		PrintLine("Going to accept next client...");
	}

	//will execute?

	PrintLine("Exiting...");

	shutdown(serverSocket, SD_BOTH);
	closesocket(serverSocket);
	WSACleanup();

	ExitWithPause(0);
}